Introduction
qBittorrent and Gluetun was the first service that I self hosted, and it was a nightmare to setup, mainly because Gluetun would constantly go unhealthy and seeding would stop. Here I will share my docker compose file and explain how I fixed the issue, to the point where it goes unhealthy maybe once in a month instead of multiple times a day.
The healthcheck duration
This was crucial. I don't know if newer versions of Gluetun fixed the issue, but back when I originally set it up the default values were way too short, and this led to Gluetun failing constantly. The fix, found digging in GitHub issues, was to set custom values for the VPN health check:
HEALTH_VPN_DURATION_INITIAL=120s
HEALTH_VPN_DURATION=30s
HEALTH_TARGET_ADDRESS=cloudflare.com:80
OpenVPN instead of WireGuard
The second most important fix was to switch from WireGuard to OpenVPN. I was reluctant because I thought the performance drop would be noticeable, but it really wasn't. OpenVPN was the only stable option. Even the increased healthcheck duration didn't work for WireGuard in my case.
Libtorrent v1
To this day I still don't know if it was needed or not, but from my previous researches picking this as the Docker image was a better choice in terms of stability. But just like with every other element, I suggest you test this yourself before.
Useful commands to troubleshoot
Grab VPN IP
docker exec -it gluetun wget -qO- ifconfig.me/ip
Grab forwarded port
docker logs gluetun 2>&1 | grep -i 'port forwarded'
My docker compose
services:
gluetun:
image: qmcgaw/gluetun:v3
container_name: gluetun
cap_add:
- NET_ADMIN
devices:
- /dev/net/tun:/dev/net/tun
ports:
- "8080:8080/tcp" # qbittorrent
environment:
- TZ=
- UPDATER_PERIOD=24h
- VPN_SERVICE_PROVIDER=protonvpn
- VPN_TYPE=${VPN_TYPE}
- BLOCK_MALICIOUS=off
- OPENVPN_USER=${OPENVPN_USER}
- OPENVPN_PASSWORD=${OPENVPN_PASSWORD}
- OPENVPN_CIPHERS=AES-256-GCM
# - WIREGUARD_PRIVATE_KEY=${WIREGUARD_PRIVATE_KEY}
- PORT_FORWARD_ONLY=on
- VPN_PORT_FORWARDING=on
- VPN_PORT_FORWARDING_UP_COMMAND=/bin/sh -c 'P="{{PORTS}}"; P="$${P%%,*}"; P="$${P%% *}"; wget -qO- --retry-connrefused --waitretry=1 --timeout=10 -t 30 --post-data "json={\"listen_port\":$${P}}" http://127.0.0.1:8080/api/v2/app/setPreferences >/dev/null && echo "qB listen_port set to $${P}"'
- SERVER_COUNTRIES=${SERVER_COUNTRIES}
- OPENVPN_MSSFIX=1400
- VPN_MTU=1400
- HEALTH_VPN_DURATION_INITIAL=120s
- HEALTH_VPN_DURATION=30s
- HEALTH_TARGET_ADDRESS=cloudflare.com:80
volumes:
- /home/user/docker/qbittorrent-gluetun/gluetun/config:/gluetun
networks:
- vpn_net
restart: unless-stopped
qbittorrent:
image: lscr.io/linuxserver/qbittorrent:libtorrentv1
container_name: qbittorrent
depends_on:
- gluetun
environment:
- PUID=1000
- PGID=1000
- TZ=Europe/Rome
- WEBUI_PORT=8080
volumes:
- /home/user/docker/qbittorrent-gluetun/qbittorrent/config:/config
- /mnt/nas/media/torrents/downloads:/downloads
restart: unless-stopped
network_mode: "service:gluetun"
# Gluetun WEB-UI is honestly not needed, I just use it to quickly check the forwarded port without using the terminal.
gluetun-webui:
image: scuzza/gluetun-webui:latest
container_name: gluetun-webui
depends_on:
- gluetun
ports:
- "3002:3000"
environment:
- GLUETUN_CONTROL_URL=http://gluetun:8000
networks:
- vpn_net
restart: unless-stopped
read_only: true
tmpfs:
- /tmp
security_opt:
- no-new-privileges:true
cap_drop:
- ALL
healthcheck:
test: ["CMD", "wget", "-qO-", "http://localhost:3000/api/health"]
interval: 30s
timeout: 5s
start_period: 10s
retries: 3
networks:
vpn_net:
driver: bridge